package framework.classification.library;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import framework.AnnuaireCocola;
import framework.HierarchyCocola;
import framework.classification.entities.ClAbstractEntity;
import framework.classification.entities.ClComponent;
import framework.classification.entities.ClComponentProvided;
import framework.classification.entities.ClComponentRequired;
import framework.classification.entities.ClFunctionProvided;
import framework.classification.entities.ClFunctionRequired;
import framework.classification.entities.ClInterfaceProvided;
import framework.classification.entities.ClInterfaceRequired;
import framework.classification.entities.lattice.erca.LatticeComponentErca;
import framework.classification.entities.lattice.erca.LatticeComponentProvided;
import framework.classification.entities.lattice.erca.LatticeComponentRequired;
import framework.classification.entities.lattice.erca.LatticeFunctionProvidedErca;
import framework.classification.entities.lattice.erca.LatticeFunctionRequiredErca;
import framework.classification.entities.lattice.erca.LatticeInterfaceProvidedErca;
import framework.classification.entities.lattice.erca.LatticeInterfaceRequiredErca;
import framework.entity.ACLComponent;
import framework.entity.ACLEntity;
import framework.entity.ACLFunction;
import framework.entity.ACLInterface;

public class RPClassification extends AbstractClassfication{


	public static String MODE = "Required_Provided";
	public Boolean ordered;

	private HashMap<String, ArrayList<ClComponentRequired>> componentsRequired;
	private HashMap<String, ArrayList<ClComponentProvided>> componentsProvided;


	public RPClassification(HierarchyCocola structure, AnnuaireCocola coco,
			String latticeGeneration,Boolean ordered) {
		super(structure, coco, latticeGeneration);
		this.ordered = ordered;
		componentsRequired = new HashMap<String, ArrayList<ClComponentRequired>>();
		componentsProvided = new HashMap<String, ArrayList<ClComponentProvided>>();

	}


	public String getmode() {return MODE;}


	public void computeClassification() {
	
		computeFunctionClassfication2();
		
		computeInterfaceClassification2();
	
		computeComponentClassification();
	
	}

	public void computeComponentClassification() {

		//on recupere la definition de tous les composants de la structure
		//dans la liste listcompo
		ArrayList<ACLComponent> listcompo = new ArrayList<ACLComponent>();
		for (String compo : getStructure().getComponentsToInterface().keySet()){
			ACLComponent aclcompo = new ACLComponent(compo);
			ArrayList<ACLInterface> intersPro = getStructure().getComponentsProvided().get(aclcompo.getName());
			ArrayList<ACLInterface> intersReq  = getStructure().getComponentsRequired().get(aclcompo.getName());
			for (ACLInterface  aclinter : intersPro){
				aclcompo.addInterfacePro(aclinter);
			}
			for (ACLInterface  aclinter : intersReq){
				aclcompo.addInterfaceReq(aclinter);
			}
			listcompo.add(aclcompo);
		}

		ClComponentRequired clreq = new ClComponentRequired(getLatticeGeneration()+"_ComponentReq",this,new LatticeComponentRequired(),listcompo);
		clreq.computeRelation();
		clreq.computeLattice();
		clComponents.add(clreq);
		//on recupere tous les composants reel
		for (String ent : clreq.getRealReduced().keySet()){
			ACLComponent aclcompo = new ACLComponent(ent,ACLFunction.MODE2);

			if (!componentsRequired.containsKey(aclcompo.getName()))
				componentsRequired.put(aclcompo.getName(),new ArrayList<ClComponentRequired>());

			if (!components.containsKey(aclcompo.getName()))
				components.put(aclcompo.getName(),new ArrayList<ClAbstractEntity>());

			if (!componentsName.containsKey(aclcompo.getName())){
				componentsName.put(aclcompo.getName(),aclcompo);
			}

			componentsRequired.get(aclcompo.getName()).add(clreq);
			components.get(aclcompo.getName()).add(clreq);
		}





		ClComponentProvided clpro = new ClComponentProvided(getLatticeGeneration()+"_ComponentPro",this,new LatticeComponentProvided(),listcompo);
		clpro.computeRelation();
		clpro.computeLattice();

		clComponents.add(clpro);
		for (String ent : clpro.getRealReduced().keySet()){
			ACLComponent aclcompo = new ACLComponent(ent,ACLFunction.MODE2);

			if (!componentsProvided.containsKey(aclcompo.getName()))
				componentsProvided.put(aclcompo.getName(),new ArrayList<ClComponentProvided>());

			if (!components.containsKey(aclcompo.getName()))
				components.put(aclcompo.getName(),new ArrayList<ClAbstractEntity>());

			if (!componentsName.containsKey(aclcompo.getName())){
				componentsName.put(aclcompo.getName(),aclcompo);

			}

			componentsProvided.get(aclcompo.getName()).add(clpro);
			components.get(aclcompo.getName()).add(clpro);
		}
	}


	public ArrayList<ACLComponent> getSubstitutionComponent(String name){
		ArrayList<ACLComponent> result = new ArrayList<ACLComponent>();

		//on verifie que le composant existe
		if (!componentsName.containsKey(name)){
			System.err.println("ERREUR::"+" Nothing Component Substitution find for "+name);
			return new ArrayList<ACLComponent>();
		}

		//on recupere les composants substituable d'un point de vue fourni
		ArrayList<String> subPro = new ArrayList<String>();
		for (ClComponentProvided clpro : componentsProvided.get(name)){
			for (String sub : clpro.getSubstituteElement(componentsName.get(name).toString())){
				ACLComponent aclcompo = new ACLComponent(sub,ACLFunction.MODE2);
				if (!subPro.contains(aclcompo.getName()))
					subPro.add(aclcompo.getName());
			}
		}

		//on recupere les composants substituable d'un point de requis
		ArrayList<String> subReq = new ArrayList<String>();
		for (ClComponentRequired clreq : componentsRequired.get(name)){
			for (String sub : clreq.getSubstituteElement(componentsName.get(name).toString())){
				ACLComponent aclcompo = new ACLComponent(sub,ACLFunction.MODE2);
				if (!subReq.contains(aclcompo.getName()))
					subReq.add(aclcompo.getName());
			}
		}

		// on fait l'intersection des deux lists
		ArrayList<String> subsName = new ArrayList<String>();
		subsName.addAll(subPro);
		subsName.retainAll(subReq);

		for (String str : subsName){

			result.add(componentsName.get(str));
		}

		if (ordered){

			Boolean add= true;
			for (ClAbstractEntity c : clComponents){
				if (c.getName().equals(name)) add = false;
			}
			ClComponent cl = new ClComponent(name,this,new LatticeComponentErca(),result);
			cl.computeRelation();
			cl.computeLattice();

			if (add){
				clComponents.add(cl);
				for (String ent : cl.getRealReduced().keySet()){
					ACLComponent aclcompo = new ACLComponent(ent,ACLFunction.MODE2);

					if (!components.containsKey(aclcompo.getName()))
						components.put(aclcompo.getName(),new ArrayList<ClAbstractEntity>());

					if (!componentsName.containsKey(aclcompo.getName())){
						componentsName.put(aclcompo.getName(),aclcompo);

					}
					components.get(aclcompo.getName()).add(cl);
				}

			}
			result = new ArrayList<ACLComponent>();
			for (String s : cl.getSubstituteElement(componentsName.get(name).toString())){
				ACLComponent aclcompo = new ACLComponent(s,ACLFunction.MODE2);
				result.add(aclcompo);

			}

		}

		return result;
	}









}
